#include "glframebufferobject.h"
#include "pfmimage.h"
#include <qopenglext.h>
#include <QFile>

GLFrameBufferObject::GLFrameBufferObject(short width, short height, short channels)
{
    w = width;
    h = height;
    c = channels;
    pBuffer = new float[w*h*c];
    fbo = 0;
    colorBuffer = 0;
    depthBuffer = 0;
    initializeGL();    
    logTextStream = NULL;
}

GLFrameBufferObject::~GLFrameBufferObject()
{
    delete[] pBuffer;
    if(colorBuffer)
        glDeleteRenderbuffers(1, &colorBuffer);
    if(depthBuffer)
        glDeleteRenderbuffers(1, &depthBuffer);
    if(fbo)
        glDeleteFramebuffers(1, &fbo);
}

bool GLFrameBufferObject::CreateFbo()
{
    if(logTextStream)
    {
        *logTextStream<<"FBO width: "<<w<<", height: "<<h<<", channel: "<<c<<"\n";
        logTextStream->flush();
    }
    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    //create color render buffer
//    CreateRGBATexture();
//    glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureID, 0);
    glGenRenderbuffers(1,&colorBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
    if(c==3)
    {
        glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB32F, w, h);
    }
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);



    //create depth buffer
    glGenRenderbuffers(1, &depthBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, w,h);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer);


    //check status
    // check if everything is OK
    GLenum e = glCheckFramebufferStatus(GL_FRAMEBUFFER);
    switch (e) {

        case GL_FRAMEBUFFER_UNDEFINED:
            //printf("FBO Undefined\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT :
            //printf("FBO Incomplete Attachment\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT :
            //printf("FBO Missing Attachment\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER :
            //printf("FBO Incomplete Draw Buffer\n");
            break;
        case GL_FRAMEBUFFER_UNSUPPORTED :
            //printf("FBO Unsupported\n");
            break;
        case GL_FRAMEBUFFER_COMPLETE:
            //printf("FBO OK\n");
            break;
        default:
            ;//printf("FBO Problem?\n");
    }

    if (e != GL_FRAMEBUFFER_COMPLETE)
        return false;
    // unbind fbo
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    return true;
}

void GLFrameBufferObject::BindFbo()
{
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);

    //the buffer selection in glDrawBuffers is part of the framebuffer object state.
    //Therefore, if this setting is constant, this function can be called only once when creating the framebuffer.
    glDrawBuffer(GL_COLOR_ATTACHMENT0);


}

void GLFrameBufferObject::initializeGL()
{
    initializeOpenGLFunctions();
}

void GLFrameBufferObject::ReleaseFbo()
{
   glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

void GLFrameBufferObject::ReadBuffer()
{
    glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
    glReadBuffer(GL_COLOR_ATTACHMENT0);
    if(c==3)
    {
        glReadPixels(0, 0, w, h, GL_RGB, GL_FLOAT, pBuffer);
    }

}

void GLFrameBufferObject::SaveBufferToFile(QString fileName)
{
    PFMImage pfm(w, h, c, pBuffer);
    pfm.WriteToFile(fileName);
}

void GLFrameBufferObject::CreateRGBATexture()
{

/*    glGenTextures(1, &textureID);

    glBindTexture(GL_TEXTURE_2D, textureID);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F,
                        w,
                        h,
                        0, GL_RGB32F, GL_FLOAT,
                        NULL);

    glBindTexture(GL_TEXTURE_2D, 0);
    */
}


void GLFrameBufferObject::CheckFboLimits()
{


    glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxColorAttachments);
    //    printf("Max Color Attachments: %d\n", res);

    glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &maxFramebufferWidth);
    //    printf("Max Framebuffer Width: %d\n", res);

    glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &maxFramebufferHeight);
        //printf("Max Framebuffer Height: %d\n", res);

    glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &maxFramebufferSamples);
        //printf("Max Framebuffer Samples: %d\n", res);

    glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &maxFramebufferLayers);
        //printf("Max Framebuffer Layers: %d\n", res);

}
